CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)
PROJECT(libucl C)

SET(LIBUCL_VERSION_MAJOR 0)
SET(LIBUCL_VERSION_MINOR 9)
SET(LIBUCL_VERSION_PATCH 2)

SET(LIBUCL_VERSION
        "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")

INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(FindOpenSSL)
INCLUDE(GNUInstallDirs)

OPTION(ENABLE_URL_INCLUDE  "Enable urls in ucl includes (requires libcurl or libfetch) [default: OFF]" OFF)
OPTION(ENABLE_URL_SIGN  "Enable signatures check in ucl includes (requires openssl) [default: OFF]" OFF)
OPTION(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF)
OPTION(ENABLE_LUA "Enable lua support [default: OFF]" OFF)
OPTION(ENABLE_LUAJIT "Enable luajit support [default: OFF]" OFF)
OPTION(ENABLE_UTILS "Enable building utility binaries [default: OFF]" OFF)

# Find lua installation
MACRO(FindLua)
	# Find lua libraries
	UNSET(LUA_INCLUDE_DIR CACHE)
	UNSET(LUA_LIBRARY CACHE)
	CMAKE_PARSE_ARGUMENTS(LUA "" "VERSION_MAJOR;VERSION_MINOR;ROOT" "" ${ARGN})

	IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR)
		MESSAGE(FATAL_ERROR "Invalid FindLua invocation: ${ARGN}")
	ENDIF()

	IF(ENABLE_LUAJIT MATCHES "ON")
		MESSAGE(STATUS "Check for luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
		FIND_PATH(LUA_INCLUDE_DIR luajit.h
				HINTS
				"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
				$ENV{LUA_DIR}
				PATH_SUFFIXES "include/luajit-2.0"
				"include/luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
				"include/luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				"include/luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				"include/luajit"
				"include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
				"include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				"include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				include/lua include
				PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS}
		)
		FIND_LIBRARY(LUA_LIBRARY
				NAMES luajit
				"luajit-2.0"
				"luajit2.0"
				"luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
				"luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				"luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				HINTS
				"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
				$ENV{LUA_DIR}
				PATH_SUFFIXES lib64 lib
				PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS}
				DOC "Lua library"
		)

		IF(NOT LUA_LIBRARY OR NOT LUA_INCLUDE_DIR)
			MESSAGE(STATUS "Fallback from luajit to plain lua")
			SET(ENABLE_LUAJIT "OFF")
			MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
			FIND_PATH(LUA_INCLUDE_DIR lua.h
					HINTS
					"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
					$ENV{LUA_DIR}
					PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
					"include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
					"include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
					include/lua include
					PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS}
			)
			FIND_LIBRARY(LUA_LIBRARY
					NAMES lua
					"lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
					"lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
					"lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
					HINTS
					"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
					$ENV{LUA_DIR}
					PATH_SUFFIXES lib64 lib
					PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS}
					DOC "Lua library"
			)
		ENDIF()
	ELSE(ENABLE_LUAJIT MATCHES "ON")
		MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
		FIND_PATH(LUA_INCLUDE_DIR lua.h
				HINTS
				"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
				$ENV{LUA_DIR}
				PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
				"include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				"include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				include/lua include
				PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS}
		)
		FIND_LIBRARY(LUA_LIBRARY
				NAMES lua
				"lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
				"lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				"lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
				HINTS
				"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
				$ENV{LUA_DIR}
				PATH_SUFFIXES lib64 lib
				PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS}
				DOC "Lua library"
		)
	ENDIF(ENABLE_LUAJIT MATCHES "ON")

	IF(LUA_LIBRARY AND LUA_INCLUDE_DIR)
		SET(LUA_FOUND 1)
		IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR)
			SET(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR})
			SET(LUA_VERSION_MINOR ${LUA_VERSION_MINOR})
		ENDIF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR)
		IF(ENABLE_LUAJIT MATCHES "ON")
			MESSAGE(STATUS "Found luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
		ELSE(ENABLE_LUAJIT MATCHES "ON")
			MESSAGE(STATUS "Found lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
		ENDIF(ENABLE_LUAJIT MATCHES "ON")
	ENDIF(LUA_LIBRARY AND LUA_INCLUDE_DIR)
ENDMACRO()

IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
	LIST(APPEND CMAKE_REQUIRED_LIBRARIES rt)
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")

IF(ENABLE_URL_INCLUDE MATCHES "ON")
    FIND_LIBRARY(LIBFETCH_LIBRARY NAMES fetch PATHS	PATH_SUFFIXES lib64 lib
                      PATHS
                          ~/Library/Frameworks
                          /Library/Frameworks
                          /usr/local
                          /usr
                          /sw
                          /opt/local
                          /opt/csw
                          /opt
                     DOC "Path where the libfetch library can be found")
    IF(LIBFETCH_LIBRARY)
    	FIND_FILE(HAVE_FETCH_H NAMES fetch.h PATHS /usr/include
    											   /opt/include
    											   /usr/local/include
    				DOC "Path to libfetch header")
    ELSE(LIBFETCH_LIBRARY)
    	# Try to find libcurl
        FIND_PACKAGE(CURL)
    	IF(NOT CURL_FOUND)
    		MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration")
    	ENDIF(NOT CURL_FOUND)
    ENDIF(LIBFETCH_LIBRARY)
ENDIF(ENABLE_URL_INCLUDE MATCHES "ON")

set(SYNC_BUILTINS_TEST_SOURCE [====[
int main()
{
    unsigned long val;

    __sync_bool_compare_and_swap(&val, 0, 1);
    __sync_add_and_fetch(&val, 1);
    __sync_fetch_and_add(&val, 0);
    __sync_sub_and_fetch(&val, 1);

    return 0;
}
]====])

CHECK_C_SOURCE_COMPILES("${SYNC_BUILTINS_TEST_SOURCE}" HAVE_ATOMIC_BUILTINS)
IF(NOT HAVE_ATOMIC_BUILTINS)
    MESSAGE(WARNING "Libucl references could be thread-unsafe because atomic builtins are missing")
ENDIF(NOT HAVE_ATOMIC_BUILTINS)

SET(CMAKE_C_WARN_FLAGS "")
CHECK_C_COMPILER_FLAG(-W SUPPORT_W)
CHECK_C_COMPILER_FLAG(-Wno-pointer-sign SUPPORT_WPOINTER_SIGN)
CHECK_C_COMPILER_FLAG(-Wno-unused-parameter SUPPORT_WUNUSED_PARAMETER)
IF(SUPPORT_W)
    SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -W")
ENDIF(SUPPORT_W)
IF(SUPPORT_WPOINTER_SIGN)
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign")
ENDIF(SUPPORT_WPOINTER_SIGN)
IF(SUPPORT_WUNUSED_PARAMETER)
	SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-unused-parameter")
ENDIF(SUPPORT_WUNUSED_PARAMETER)

SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_WARN_FLAGS}" )

IF(ENABLE_URL_SIGN MATCHES "ON")
	IF(OPENSSL_FOUND)
		SET(HAVE_OPENSSL 1)
		INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}")
	ENDIF(OPENSSL_FOUND)
ENDIF(ENABLE_URL_SIGN MATCHES "ON")

SET(UCL_COMPILE_DEFS)
IF(HAVE_FETCH_H)
    LIST(APPEND UCL_COMPILE_DEFS -DHAVE_FETCH_H=1)
ENDIF(HAVE_FETCH_H)
IF(CURL_FOUND)
    LIST(APPEND UCL_COMPILE_DEFS -DCURL_FOUND=1)
ENDIF(CURL_FOUND)
IF(HAVE_OPENSSL)
    LIST(APPEND UCL_COMPILE_DEFS -DHAVE_OPENSSL=1)
ENDIF(HAVE_OPENSSL)
IF(HAVE_ATOMIC_BUILTINS)
    LIST(APPEND UCL_COMPILE_DEFS -DHAVE_ATOMIC_BUILTINS=1)
ENDIF(HAVE_ATOMIC_BUILTINS)

SET(UCLSRC src/ucl_util.c
		src/ucl_parser.c
		src/ucl_emitter.c
		src/ucl_emitter_streamline.c
		src/ucl_emitter_utils.c
		src/ucl_hash.c
		src/ucl_schema.c
		src/ucl_msgpack.c
		src/ucl_sexp.c)

SET(UCLHDR include/ucl.h
		include/ucl++.h)

SET (LIB_TYPE STATIC)
IF (BUILD_SHARED_LIBS)
  SET (LIB_TYPE SHARED)
ENDIF (BUILD_SHARED_LIBS)
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
ADD_LIBRARY(ucl::ucl ALIAS ucl)
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
TARGET_INCLUDE_DIRECTORIES(ucl
        PUBLIC
          $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
          $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
        PRIVATE
          ${CMAKE_CURRENT_SOURCE_DIR}/src
          ${CMAKE_CURRENT_SOURCE_DIR}/uthash
          ${CMAKE_CURRENT_SOURCE_DIR}/klib)
TARGET_COMPILE_DEFINITIONS(ucl
    PRIVATE
    ${UCL_COMPILE_DEFS}
)

IF(ENABLE_LUA MATCHES "ON")
	IF(ENABLE_LUAJIT MATCHES "ON")
		FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}")
		IF(NOT LUA_FOUND)
			MESSAGE(FATAL_ERROR "Lua not found, lua support is required")
		ELSE(NOT LUA_FOUND)
			INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
		ENDIF(NOT LUA_FOUND)
	ELSE(ENABLE_LUAJIT MATCHES "ON")
		FindLua(VERSION_MAJOR "5" VERSION_MINOR "2" ROOT "${LUA_ROOT}")
		IF(NOT LUA_FOUND)
			FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}")
		ENDIF(NOT LUA_FOUND)
		IF(NOT LUA_FOUND)
			MESSAGE(FATAL_ERROR "Lua not found, lua support is required")
		ELSE(NOT LUA_FOUND)
			INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
		ENDIF(NOT LUA_FOUND)
	ENDIF(ENABLE_LUAJIT MATCHES "ON")
	SET(UCL_LUA_SRC lua/lua_ucl.c)
	ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
	ADD_LIBRARY(ucl::lua ALIAS lua-ucl)
	IF(ENABLE_LUAJIT MATCHES "ON")
		TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
	ELSE(ENABLE_LUAJIT MATCHES "ON")
		TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}")
	ENDIF(ENABLE_LUAJIT MATCHES "ON")
	TARGET_LINK_LIBRARIES(lua-ucl ucl)
	TARGET_INCLUDE_DIRECTORIES(lua-ucl PUBLIC include PRIVATE src uthash)
	SET_TARGET_PROPERTIES(lua-ucl PROPERTIES
		VERSION ${LIBUCL_VERSION}
		SOVERSION ${LIBUCL_VERSION_MAJOR}
		PUBLIC_HEADER include/lua_ucl.h)
	INSTALL(TARGETS lua-ucl DESTINATION ${CMAKE_INSTALL_LIBDIR}
			PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
ENDIF()

IF(HAVE_FETCH_H)
    TARGET_LINK_LIBRARIES(ucl fetch)
ELSE(HAVE_FETCH_H)
    IF(CURL_FOUND)
        TARGET_LINK_LIBRARIES(ucl ${CURL_LIBRARIES})
    ENDIF(CURL_FOUND)
ENDIF(HAVE_FETCH_H)
IF(ENABLE_URL_SIGN MATCHES "ON")
	IF(OPENSSL_FOUND)
		TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES})
	ENDIF(OPENSSL_FOUND)
ENDIF(ENABLE_URL_SIGN MATCHES "ON")

IF(UNIX)
    TARGET_LINK_LIBRARIES(ucl -lm)
ENDIF(UNIX)

SET_TARGET_PROPERTIES(ucl PROPERTIES
	PUBLIC_HEADER "${UCLHDR}")

INSTALL(TARGETS ucl EXPORT uclConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}
		PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

IF(ENABLE_UTILS MATCHES "ON")
    ADD_SUBDIRECTORY(utils)
ENDIF()

install(EXPORT uclConfig
	FILE ucl-config.cmake
	NAMESPACE ucl::
	DESTINATION "share/ucl"
)

